package com.cyyl.updater.download

import android.app.DownloadManager
import android.content.Context
import android.content.IntentFilter
import android.database.Cursor
import android.net.Uri
import android.os.Environment
import com.cyyl.updater.AppUpdaterBuilder
import com.cyyl.updater.download.receiver.DownloadBroadcastReceiver
import com.cyyl.updater.preferences.PreferencesHelper
import kotlinx.coroutines.*

/**
 * Created on 2019/12/23
 * Title:
 * Description:
 *
 * @author Android-张康
 */
internal object DownloadUpdate {
    private const val SP_KEYS_LAST_DOWNLOAD_ID = "last_download_id"

    fun updateByInternal(
        appUpdaterBuilder: AppUpdaterBuilder,
    ): Boolean {
        return downloadApkByDownloadManager(appUpdaterBuilder)
    }

    /**
     * 通过DownloadManager下载
     * 参考[https://blog.csdn.net/johnny901114/article/details/51472600]
     * [https://www.jianshu.com/p/7ad92b3d9069]
     * @param appUpdaterBuilder 下载信息
     */
    private fun downloadApkByDownloadManager(
        appUpdaterBuilder: AppUpdaterBuilder,
    ): Boolean {
        val downloadUrl = appUpdaterBuilder.getDownloadUrl()
        val fileName = appUpdaterBuilder.getFileName()
        if (downloadUrl.isNullOrEmpty() || fileName.isNullOrEmpty()) {
            return false
        }
        val context = appUpdaterBuilder.getContext()
        val title = appUpdaterBuilder.getTitle()
        val description = appUpdaterBuilder.getDescription()
        val lastDownloadId = PreferencesHelper.decode(context, SP_KEYS_LAST_DOWNLOAD_ID, -1L)
        if (checkStatus(context, lastDownloadId)) {
            startMonitorProgress(context, lastDownloadId, appUpdaterBuilder = appUpdaterBuilder)
            return true
        }
        //注册下载完成监听
        context.registerReceiver(
            DownloadBroadcastReceiver(),
            IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE)
        )
        val request =
            DownloadManager.Request(Uri.parse(downloadUrl))
                //设置下载的路径 外部缓存路径
                .setDestinationInExternalFilesDir(
                    context,
                    Environment.DIRECTORY_DOWNLOADS,
                    fileName
                )
                //下载的标题,会在通知中显示
                .setTitle(title)
                //下载的描述，会在通知中显示
                .setDescription(description)
                //设置通知的显示方式
                .setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED)
                //设置下载的类型
                .setMimeType("application/vnd.android.package-archive")
        val downloadManager = context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
        //将最后一次下载的id保存到本地
        val enqueue = downloadManager.enqueue(request)
        PreferencesHelper.encode(context, SP_KEYS_LAST_DOWNLOAD_ID, enqueue)
        startMonitorProgress(context, enqueue, appUpdaterBuilder = appUpdaterBuilder)
        return true
    }

    /**
     * 检查是否已经有下载过的文件
     *
     * @param context 上下文
     * @param lastDownloadId 最后的下载ID
     *
     */
    private fun checkStatus(context: Context, lastDownloadId: Long): Boolean {
        if (lastDownloadId != -1L) {
            val query = DownloadManager.Query()
            query.setFilterById(lastDownloadId)
            val downloadManager =
                context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
            var cursor: Cursor? = null
            try {
                cursor = downloadManager.query(query)
                if (cursor.moveToFirst()) {
                    val status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))
                    when (status) {
                        //下载暂停
                        DownloadManager.STATUS_PAUSED -> {
                            //不做处理
                            return true
                        }
                        //下载延迟
                        DownloadManager.STATUS_PENDING -> {
                            //不做处理
                            return true
                        }
                        //正在下载
                        DownloadManager.STATUS_RUNNING -> {
                            //不做处理
                            return true
                        }
                        //下载完成
                        DownloadManager.STATUS_SUCCESSFUL -> {
                            downloadManager.getUriForDownloadedFile(lastDownloadId)?.let {
                                //判断是否能能够更新，如果能够更新，就去更新，否则就删除下载记录
                                if (InstallApkHelper.checkCanUpdate(context, it)) {
                                    InstallApkHelper.installApk(
                                        context,
                                        downloadFileUri = it
                                    )
                                    return true
                                } else {
                                    //移除掉下载记录
                                    downloadManager.remove(lastDownloadId)
                                }
                            }
                        }
                        //下载失败
                        DownloadManager.STATUS_FAILED -> {
                            //移除掉下载记录
                            downloadManager.remove(lastDownloadId)
                            return false
                        }
                    }
                }
            } finally {
                cursor?.close()
            }
        }
        return false
    }

    /**
     * 开始监听进度 每隔两秒发送一次进度，直到下载完成
     *
     * @param context 上下文
     * @param downloadId 下载的ID
     * @param appUpdaterBuilder 下载信息
     */
    private fun startMonitorProgress(
        context: Context,
        downloadId: Long,
        appUpdaterBuilder: AppUpdaterBuilder
    ) {
        getCoroutineScope(context).launch(Dispatchers.IO) {
            val downloadManager =
                context.getSystemService(Context.DOWNLOAD_SERVICE) as DownloadManager
            val query = DownloadManager.Query().setFilterById(downloadId)
            while (true) {
                val cursor: Cursor = downloadManager.query(query)
                if (cursor.moveToFirst()) {
                    val status = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_STATUS))
                    //下载成功
                    if (status == DownloadManager.STATUS_SUCCESSFUL) {
                        appUpdaterBuilder.downloadProgressFlow.emit(
                            Triple(
                                DownloadManager.STATUS_SUCCESSFUL,
                                100,
                                null
                            )
                        )
                        break
                    }
                    //下载失败
                    if (status == DownloadManager.STATUS_FAILED) {
                        //查询错误信息
                        val errorMessage: String =
                            cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_REASON))
                        appUpdaterBuilder.downloadProgressFlow.emit(
                            Triple(
                                DownloadManager.STATUS_FAILED,
                                0,
                                errorMessage
                            )
                        )
                        break
                    }
                    //其他非下载状态，暂时跳过
                    if (status != DownloadManager.STATUS_RUNNING) {
                        continue
                    }
                    //正在下载中
                    val totalSize =
                        cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES))
                    val downloadSize =
                        cursor.getLong(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR))
                    val process = (downloadSize.toDouble() / totalSize.toDouble() * 100).toInt()
                    appUpdaterBuilder.downloadProgressFlow.emit(
                        Triple(
                            DownloadManager.STATUS_RUNNING,
                            process,
                            null
                        )
                    )
                }
                //每隔两秒，查询一次下载结果
                delay(2000)
            }
            //当前返回一个MainScope,需要我们手动取消掉
            cancel()
        }
    }

    /**
     * 获取一个协程上下文
     *
     * @param context 暂时无用
     * @return 返回一个协程上下文
     */
    private fun getCoroutineScope(context: Context): CoroutineScope {
        return MainScope()
    }

}